package net.lesscoding.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import net.lesscoding.common.ColumnInfo;
import net.lesscoding.common.CommonConst;
import net.lesscoding.common.TableInfo;
import net.lesscoding.config.RegExrConfig;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author eleven
 * @date 2022/8/9 13:27
 * @description  sql解析工具类
 */
public abstract class ParseUtil {

    /**
     * 解析单条sql
     * @param sql sql语句
     * @return
     */
    public abstract TableInfo parseSql(String sql);

    /**
     * 解析sql建表语句集合
     * @param sqlList
     * @return
     */
    public abstract List<TableInfo> parseSql(List<String> sqlList);


    /**
     * 直接解析数据库管理工具导出的sql文件
     * @param sql
     * @return
     */
    public abstract List<TableInfo> parseExportSql(String sql);

    /**
     * 根据dataType或者字段的数据类型
     * @param dataType  数据库解析出来的类型
     * @return Stirng   实体类实际上需要用的参数
     */
    public abstract String getFieldTypeByDataType(String dataType);

    /**
     * 获取字段的注释
     * @param columnStr   注释
     * @return
     */
    public abstract String getComment(String columnStr);

    public void getComment(String columnStr, String commentStr) {

    }

    /**
     * 判断一个字符串是不是以数字结尾或者以数字开头
     * @param str           要判断的字符串
     * @param startType     true 判断开头字符 false 判断结尾字符
     * @return Boolean
     */
    public Boolean isNumberEndOrStart(String str,Boolean startType){
        char validChar = startType ? str.charAt(0) : str.charAt(str.length() - 1);
        return validChar >= '0' && validChar <= '9';
    }

    /**
     * 获取所有的字段
     * @param sql   sql语句
     * @return
     */
    public List<String> getAllColumn(String sql){

        // 按照 , 分割开获取字段集合
        List<String> colList = Arrays.asList(sql.trim().split(CommonConst.COMMA));
        LinkedList<String> columnStrList = new LinkedList<>();
        columnStrList.addAll(colList);
        List<Integer> errorList = new ArrayList<>();
        /**
         *  如果当前行以数字结尾，并且下一行以数字开头，则放置到错误集合中
         *  因为按照了 , 进行分割，如果出现double(5,2)这种就会变成行数据
         */
        for (int i = 1; i < columnStrList.size(); i++) {
            String prev = columnStrList.get(i - 1).trim();
            String next = columnStrList.get(i).trim();
            if(isNumberEndOrStart(prev,false) && isNumberEndOrStart(next,true)){
                errorList.add(i);
            }
        }
        /**
         * 将double这种错误分割的数据重新拼接成一行，然后将以数字开头的数据删除掉
         */
        for (int index : errorList) {
            String next = columnStrList.get(index).trim();
            String prev = columnStrList.get(index - 1).trim();
            prev = prev + ',' + next;
            columnStrList.set(index - 1,prev);
            columnStrList.remove(index);
        }
        return columnStrList;
    }

    /**
     * 获取表字段的公共属性
     * @param tableInfoList     表集合
     * @return  List            返回所有表字段的公共集合
     */
    public List<ColumnInfo> getCommonProperty(List<TableInfo> tableInfoList){
        if(CollUtil.isNotEmpty(tableInfoList)) {
            List<List<ColumnInfo>> allColumnList = new ArrayList<>(tableInfoList.size());
            tableInfoList.forEach(item -> allColumnList.add(item.getColumnList()));
            List<ColumnInfo> resultList = allColumnList.get(0);
            allColumnList.forEach(item -> resultList.retainAll(item));
            return resultList;
        }
        return new ArrayList<>();
    }

    /**
     * 获取列定义中的主键字段
     * @param keyStrList  解析到的数据库列字段集合
     * @return String 主键的列名
     */
    public String getKeyCol(List<String> keyStrList){
        List<String> inColKeyList = keyStrList.stream()
                .filter(item -> ReUtil.isMatch(RegExrConfig.MYSQL_IN_COL_PRIMARY_KEY, item))
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(inColKeyList)){
            return getKeyForInColStr(inColKeyList.get(0));
        }
        List<String> keyList = keyStrList.stream()
                .filter(item -> ReUtil.isMatch(RegExrConfig.MYSQL_PRIMARY_KEY, item))
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(keyList)){
            return getKeyColumn(keyList.get(0));
        }
        return null;
    }

    /**
     * 从primary key在列定义的字段中获取主键字段
     * id int(11) default 0 auto_increment primary key comment 'test'
     * 先将传入的列定义字符串trim去除前后空格，然后按照空格分割取第一个字符串即可
     * @param columnStr   传入的列定义字符串
     * @return String
     */
    private String getKeyForInColStr(String columnStr){
        columnStr = columnStr.trim();
        String[] split = columnStr.split(CommonConst.WHITE_SPACE);
        return split[0];
    }

    /**
     * 获取主键里边的值
     * @param keyStr
     * @return
     */
    private String getKeyColumn(String keyStr){
        int leftBracket = keyStr.indexOf(CommonConst.LEFT_BRACKET);
        int rightBracket = keyStr.indexOf(CommonConst.RIGHT_BRACKET);
        return keyStr.substring(leftBracket + 1,rightBracket);
    }
}
